
#ifndef QL_NS
#error QL_NS is not defined
#endif

#ifndef QL_ELEMENT_TYPE
#error QL_ELEMENT_TYPE is not defined
#endif

#include <stdlib.h>

struct QL_NS(ForeachContext)
{
    QL_ELEMENT_TYPE * fill_arr;
    size_t current;
    size_t total;
    bool overflow;
};

static void QL_NS(foreach_cb)(void * c, QL_ELEMENT_TYPE * e)
{
    struct QL_NS(ForeachContext) * fc = (struct QL_NS(ForeachContext) *)c;
    if (fc->current < fc->total)
    {
        fc->fill_arr[fc->current++] = *e;
    }
    else
    {
        fc->overflow = true;
    }
}

static int QL_NS(internal_elements_compare)(const void * lhs, const void * rhs)
{
    const QL_ELEMENT_TYPE l = *((const QL_ELEMENT_TYPE *)lhs);
    const QL_ELEMENT_TYPE r = *((const QL_ELEMENT_TYPE *)rhs);

    return (int)(l - r);
}

static void QL_NS(test_foreach)(const char * test_name, QL_NS(Allocator) * allocator, QL_ELEMENT_TYPE * arr, size_t total)
{
    struct QL_NS(ForeachContext) fc = { 0 };

    QL_UT_BEGIN(test_name);

    fc.fill_arr = ql_mallocz(sizeof(QL_ELEMENT_TYPE) * total);
    fc.total = total;

    QL_NS(allocator_foreach)(allocator, &fc, &QL_NS(foreach_cb));

    QL_UT_VERIFY_SILENT(fc.current == total);
    QL_UT_VERIFY_SILENT(!fc.overflow);

    if ((fc.current == total) && !fc.overflow)
    {
        size_t i;

        qsort(fc.fill_arr, fc.total, sizeof(QL_ELEMENT_TYPE), &QL_NS(internal_elements_compare));

        for (i = 0; i < total; ++i)
        {
            QL_ELEMENT_TYPE key = arr[i];
            void * found_elem_p = bsearch(&key, fc.fill_arr, fc.total,
                sizeof(QL_ELEMENT_TYPE), &QL_NS(internal_elements_compare));

            QL_UT_VERIFY_SILENT(found_elem_p != NULL);
        }
    }

    {
        size_t used;
        size_t allocated;

        QL_NS(get_allocator_status)(allocator, &used, &allocated);
        QL_UT_VERIFY_SILENT(used == total);
    }

    ql_free(fc.fill_arr);
    QL_UT_END();
}



#undef QL_NS
#undef QL_ELEMENT_TYPE
